﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Blob;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Script.Serialization;
using System.Security.Policy;
using System.Text;

namespace LoadGenerator
{
    public class InvokeJob
    {
        private Job job;

        private Dictionary<string, object> strings;
        private List<object> ParameterListForInvoke;
        private Type service;
        private MethodInfo mi;
        private object ServiceInstance;

        //private const string tableSamples = "INVOKESamples";
        //private CloudTable CloudTableSamples;

        public InvokeJob(Job _job)
        {
            job = _job;
            
            //Delete and create job table
            //LoadController.AzureTableHelper.DeleteTable(connectionString, tableSamples);
            //LoadController.AzureTableHelper.CreateTable(connectionString, tableSamples);
            //CloudTableSamples = LoadController.AzureTableHelper.GetCloudTable(connectionString, tableSamples);
            
            Assembly theAssembly = null;
            if (AppDomain.CurrentDomain.GetAssemblies().Where(assembly => assembly.ManifestModule.Name == job.DllName).Count() == 0)
            {
                CloudBlobContainer containerAss = AzureBlobHelper.GetContainerReference(AppSettings.BlobContainer_assemblies);
                AzureBlobHelper.DownloadBlobToPath(containerAss, job.DllName, Path.GetTempPath());

                theAssembly = Assembly.LoadFrom(Path.GetTempPath() + job.DllName);
            }
            else
            {
                theAssembly = AppDomain.CurrentDomain.GetAssemblies().Where(assembly => assembly.ManifestModule.Name == job.DllName).FirstOrDefault();
            }

            this.service = theAssembly.GetType(job.ClassName);
            this.mi = service.GetMethod(job.MethodName);
            this.ServiceInstance = Activator.CreateInstance(service);

            ParameterInfo[] pi = mi.GetParameters();
            List<object> ParameterListForInvoke = new List<object>();
            foreach (ParameterInfo pii in pi)
            {
                object obj = LoadController.InvokeHelper.CreateNewInstance(pii.ParameterType);
                ParameterListForInvoke.Add(obj);
            }
            this.ParameterListForInvoke = ParameterListForInvoke;

            JavaScriptSerializer jsSerializer = new JavaScriptSerializer(new LoadController.CustomTypeResolver());
            //this.strings = (Dictionary<string, object>)jsSerializer.Deserialize(job.Parameters, typeof(Dictionary<string, object>));
            object objDeserialized = jsSerializer.DeserializeObject(job.Parameters);
            this.strings = (Dictionary<string, object>)objDeserialized;
        }

        public void Do(Sample t)
        {
            System.Diagnostics.Stopwatch ResponseStopWatch = new System.Diagnostics.Stopwatch();

            //map values of controls to invoke parameters
            if (job.IsRandomInvoke)
                LoadController.InvokeHelper.MapRandomInvoke(strings, ref ParameterListForInvoke);
            else
            {
                //TODO
            }

            object[] objs = ParameterListForInvoke.ToArray();

            try
            {
                ResponseStopWatch.Start();
                object result = mi.Invoke(ServiceInstance, objs);
                Thread.Sleep(3000);
                //this.DoTestInvoke();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.ToString());
                t.hasError = true;
            }

            ResponseStopWatch.Stop();

            t.ResponseTime = (int)Math.Round(ResponseStopWatch.Elapsed.TotalMilliseconds);            
        }

        public void DoTestInvoke()
        {
            //SOAP Request bilden
            WebRequest httpRequest = WebRequest.Create("http://www.webservicex.net/stockquote.asmx");
            httpRequest.Method = "POST";
            httpRequest.ContentType = "text/xml; charset=utf-8";
            httpRequest.Headers.Add("SOAPAction: http://www.webserviceX.NET/GetQuote");
            httpRequest.Credentials = CredentialCache.DefaultCredentials;

            Stream thestream = httpRequest.GetRequestStream();
            StreamWriter streamWriter = new StreamWriter(thestream, Encoding.ASCII);

            string soapmessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetQuote xmlns=\"http://www.webserviceX.NET/\"><symbol>AAPL</symbol></GetQuote></soap:Body></soap:Envelope>";

            streamWriter.Write(soapmessage);
            streamWriter.Close();

            //Get the Response    
            HttpWebResponse wr = (HttpWebResponse)httpRequest.GetResponse();

            if (wr.StatusCode == HttpStatusCode.OK)
            {
                //No error
            }
            else
            {
                //error
            }

            Stream srd = wr.GetResponseStream();
            StreamReader rdr = new StreamReader(srd);
            string text = rdr.ReadToEnd();
            
        }

        public void WriteSOAPMessagesToTable()
        {
            //DEBUG
            //Reading the logfile to get request and response stream
            string filename = Path.GetTempPath() + mi.DeclaringType.FullName + ".log";
            if (File.Exists(filename))
            {
                bool IsRequestLine = false;

                string request = String.Empty;
                string response = String.Empty;

                foreach (string line in File.ReadLines(filename))
                {
                    if (line.StartsWith("-----SoapRequest"))
                    {
                        IsRequestLine = true;
                        continue;
                    }

                    if (line.StartsWith("-----SoapResponse"))
                    {
                        IsRequestLine = false;
                        continue;
                    }

                    if (IsRequestLine)
                        request += line;
                    else
                        response += line;
                }

                //LoadController.TEST.Sample requestEntity = new LoadController.TEST.Sample(job.RowKey, "request", request);
                //LoadController.TEST.Sample responseEntity = new LoadController.TEST.Sample(job.RowKey, "response", response);

                ////Insert sample to table
                //LoadController.AzureTableHelper.InsertEntity(requestEntity, CloudTableSamples);
                //LoadController.AzureTableHelper.InsertEntity(responseEntity, CloudTableSamples);
            }
        }

        public void Uninitialize()
        {
            //Delete log file
            string filename = Path.GetTempPath() + mi.DeclaringType.FullName + ".log";
            File.Delete(filename);

            //reset properties
            this.strings = null;
            this.ParameterListForInvoke = null;
            this.service = null;
            this.mi = null;


        }
    }
}
